//: net/mindview/util/Countries.java
// "Flyweight" Maps and Lists of sample data.
package net.mindview.util;

import java.util.*;
import java.util.Map.Entry;

import static net.mindview.util.Print.*;

public class Countries {
    public static final String[][] DATA = {
            // Africa
            { "ALGERIA", "Algiers" },
            { "ANGOLA", "Luanda" },
            { "BENIN", "Porto-Novo" },
            { "BOTSWANA", "Gaberone" },
            { "BURKINA FASO", "Ouagadougou" },
            { "BURUNDI", "Bujumbura" },
            { "CAMEROON", "Yaounde" },
            { "CAPE VERDE", "Praia" },
            { "CENTRAL AFRICAN REPUBLIC", "Bangui" },
            { "CHAD", "N'djamena" },
            { "COMOROS", "Moroni" },
            { "CONGO", "Brazzaville" },
            { "DJIBOUTI", "Dijibouti" },
            { "EGYPT", "Cairo" },
            { "EQUATORIAL GUINEA", "Malabo" },
            { "ERITREA", "Asmara" },
            { "ETHIOPIA", "Addis Ababa" },
            { "GABON", "Libreville" },
            { "THE GAMBIA", "Banjul" },
            { "GHANA", "Accra" },
            { "GUINEA", "Conakry" },
            { "BISSAU", "Bissau" },
            { "COTE D'IVOIR (IVORY COAST)", "Yamoussoukro" },
            { "KENYA", "Nairobi" },
            { "LESOTHO", "Maseru" },
            { "LIBERIA", "Monrovia" },
            { "LIBYA", "Tripoli" },
            { "MADAGASCAR", "Antananarivo" },
            { "MALAWI", "Lilongwe" },
            { "MALI", "Bamako" },
            { "MAURITANIA", "Nouakchott" },
            { "MAURITIUS", "Port Louis" },
            { "MOROCCO", "Rabat" },
            { "MOZAMBIQUE", "Maputo" },
            { "NAMIBIA", "Windhoek" },
            { "NIGER", "Niamey" },
            { "NIGERIA", "Abuja" },
            { "RWANDA", "Kigali" },
            { "SAO TOME E PRINCIPE", "Sao Tome" },
            { "SENEGAL", "Dakar" },
            { "SEYCHELLES", "Victoria" },
            { "SIERRA LEONE", "Freetown" },
            { "SOMALIA", "Mogadishu" },
            { "SOUTH AFRICA", "Pretoria/Cape Town" },
            { "SUDAN", "Khartoum" },
            { "SWAZILAND", "Mbabane" },
            { "TANZANIA", "Dodoma" },
            { "TOGO", "Lome" },
            { "TUNISIA", "Tunis" },
            { "UGANDA", "Kampala" },
            { "DEMOCRATIC REPUBLIC OF THE CONGO (ZAIRE)", "Kinshasa" },
            { "ZAMBIA", "Lusaka" },
            { "ZIMBABWE", "Harare" },
            // Asia
            { "AFGHANISTAN", "Kabul" },
            { "BAHRAIN", "Manama" },
            { "BANGLADESH", "Dhaka" },
            { "BHUTAN", "Thimphu" },
            { "BRUNEI", "Bandar Seri Begawan" },
            { "CAMBODIA", "Phnom Penh" },
            { "CHINA", "Beijing" },
            { "CYPRUS", "Nicosia" },
            { "INDIA", "New Delhi" },
            { "INDONESIA", "Jakarta" },
            { "IRAN", "Tehran" },
            { "IRAQ", "Baghdad" },
            { "ISRAEL", "Jerusalem" },
            { "JAPAN", "Tokyo" },
            { "JORDAN", "Amman" },
            { "KUWAIT", "Kuwait City" },
            { "LAOS", "Vientiane" },
            { "LEBANON", "Beirut" },
            { "MALAYSIA", "Kuala Lumpur" },
            { "THE MALDIVES", "Male" },
            { "MONGOLIA", "Ulan Bator" },
            { "MYANMAR (BURMA)", "Rangoon" },
            { "NEPAL", "Katmandu" },
            { "NORTH KOREA", "P'yongyang" },
            { "OMAN", "Muscat" },
            { "PAKISTAN", "Islamabad" },
            { "PHILIPPINES", "Manila" },
            { "QATAR", "Doha" },
            { "SAUDI ARABIA", "Riyadh" },
            { "SINGAPORE", "Singapore" },
            { "SOUTH KOREA", "Seoul" },
            { "SRI LANKA", "Colombo" },
            { "SYRIA", "Damascus" },
            { "TAIWAN (REPUBLIC OF CHINA)", "Taipei" },
            { "THAILAND", "Bangkok" },
            { "TURKEY", "Ankara" },
            { "UNITED ARAB EMIRATES", "Abu Dhabi" },
            { "VIETNAM", "Hanoi" },
            { "YEMEN", "Sana'a" },
            // Australia and Oceania
            { "AUSTRALIA", "Canberra" },
            { "FIJI", "Suva" },
            { "KIRIBATI", "Bairiki" },
            { "MARSHALL ISLANDS", "Dalap-Uliga-Darrit" },
            { "MICRONESIA", "Palikir" },
            { "NAURU", "Yaren" },
            { "NEW ZEALAND", "Wellington" },
            { "PALAU", "Koror" },
            { "PAPUA NEW GUINEA", "Port Moresby" },
            { "SOLOMON ISLANDS", "Honaira" },
            { "TONGA", "Nuku'alofa" },
            { "TUVALU", "Fongafale" },
            { "VANUATU", "< Port-Vila" },
            { "WESTERN SAMOA", "Apia" },
            // Eastern Europe and former USSR
            { "ARMENIA", "Yerevan" },
            { "AZERBAIJAN", "Baku" },
            { "BELARUS (BYELORUSSIA)", "Minsk" },
            { "BULGARIA", "Sofia" },
            { "GEORGIA", "Tbilisi" },
            { "KAZAKSTAN", "Almaty" },
            { "KYRGYZSTAN", "Alma-Ata" },
            { "MOLDOVA", "Chisinau" },
            { "RUSSIA", "Moscow" },
            { "TAJIKISTAN", "Dushanbe" },
            { "TURKMENISTAN", "Ashkabad" },
            { "UKRAINE", "Kyiv" },
            { "UZBEKISTAN", "Tashkent" },
            // Europe
            { "ALBANIA", "Tirana" }, { "ANDORRA", "Andorra la Vella" },
            { "AUSTRIA", "Vienna" }, { "BELGIUM", "Brussels" },
            { "BOSNIA", "-" },
            { "HERZEGOVINA", "Sarajevo" },
            { "CROATIA", "Zagreb" },
            { "CZECH REPUBLIC", "Prague" },
            { "DENMARK", "Copenhagen" },
            { "ESTONIA", "Tallinn" },
            { "FINLAND", "Helsinki" },
            { "FRANCE", "Paris" },
            { "GERMANY", "Berlin" },
            { "GREECE", "Athens" },
            { "HUNGARY", "Budapest" },
            { "ICELAND", "Reykjavik" },
            { "IRELAND", "Dublin" },
            { "ITALY", "Rome" },
            { "LATVIA", "Riga" },
            { "LIECHTENSTEIN", "Vaduz" },
            { "LITHUANIA", "Vilnius" },
            { "LUXEMBOURG", "Luxembourg" },
            { "MACEDONIA", "Skopje" },
            { "MALTA", "Valletta" },
            { "MONACO", "Monaco" },
            { "MONTENEGRO", "Podgorica" },
            { "THE NETHERLANDS", "Amsterdam" },
            { "NORWAY", "Oslo" },
            { "POLAND", "Warsaw" },
            { "PORTUGAL", "Lisbon" },
            { "ROMANIA", "Bucharest" },
            { "SAN MARINO", "San Marino" },
            { "SERBIA", "Belgrade" },
            { "SLOVAKIA", "Bratislava" },
            { "SLOVENIA", "Ljuijana" },
            { "SPAIN", "Madrid" },
            { "SWEDEN", "Stockholm" },
            { "SWITZERLAND", "Berne" },
            { "UNITED KINGDOM", "London" },
            { "VATICAN CITY", "---" },
            // North and Central America
            { "ANTIGUA AND BARBUDA", "Saint John's" }, { "BAHAMAS", "Nassau" },
            { "BARBADOS", "Bridgetown" }, { "BELIZE", "Belmopan" },
            { "CANADA", "Ottawa" }, { "COSTA RICA", "San Jose" },
            { "CUBA", "Havana" }, { "DOMINICA", "Roseau" },
            { "DOMINICAN REPUBLIC", "Santo Domingo" },
            { "EL SALVADOR", "San Salvador" },
            { "GRENADA", "Saint George's" },
            { "GUATEMALA", "Guatemala City" },
            { "HAITI", "Port-au-Prince" },
            { "HONDURAS", "Tegucigalpa" },
            { "JAMAICA", "Kingston" },
            { "MEXICO", "Mexico City" },
            { "NICARAGUA", "Managua" },
            { "PANAMA", "Panama City" },
            { "ST. KITTS", "-" },
            { "NEVIS", "Basseterre" },
            { "ST. LUCIA", "Castries" },
            { "ST. VINCENT AND THE GRENADINES", "Kingstown" },
            { "UNITED STATES OF AMERICA", "Washington, D.C." },
            // South America
            { "ARGENTINA", "Buenos Aires" },
            { "BOLIVIA", "Sucre (legal)/La Paz(administrative)" },
            { "BRAZIL", "Brasilia" }, { "CHILE", "Santiago" },
            { "COLOMBIA", "Bogota" }, { "ECUADOR", "Quito" },
            { "GUYANA", "Georgetown" }, { "PARAGUAY", "Asuncion" },
            { "PERU", "Lima" }, { "SURINAME", "Paramaribo" },
            { "TRINIDAD AND TOBAGO", "Port of Spain" },
            { "URUGUAY", "Montevideo" }, { "VENEZUELA", "Caracas" }, };

    // Use AbstractMap by implementing entrySet()
    private static class FlyweightMap extends AbstractMap<String, String> {
        private static class Entry implements Map.Entry<String, String> {
            int index;

            Entry(int index) {
                this.index = index;
            }

            public boolean equals(Object o) {
                return DATA[index][0].equals(o);
            }

            public String getKey() {
                return DATA[index][0];
            }

            public String getValue() {
                return DATA[index][1];
            }

            public String setValue(String value) {
                throw new UnsupportedOperationException();
            }

            public int hashCode() {
                return DATA[index][0].hashCode();
            }
        }

        // Use AbstractSet by implementing size() & iterator()
        static class EntrySet extends AbstractSet<Map.Entry<String, String>> {
            @Override
            public Spliterator<Map.Entry<String, String>> spliterator() {
                return null;
            }

            private int size;

            EntrySet(int size) {
                if (size < 0)
                    this.size = 0;
                // Can't be any bigger than the array:
                else if (size > DATA.length)
                    this.size = DATA.length;
                else
                    this.size = size;
            }

            public int size() {
                return size;
            }

            private class Iter implements Iterator<Map.Entry<String, String>> {
                // Only one Entry object per Iterator:
                private Entry entry = new Entry(-1);

                public boolean hasNext() {
                    return entry.index < size - 1;
                }

                public Map.Entry<String, String> next() {
                    entry.index++;
                    return entry;
                }

                public void remove() {
                    throw new UnsupportedOperationException();
                }
            }

            public Iterator<Map.Entry<String, String>> iterator() {
                return new Iter();
            }
        }

        private static Set<Map.Entry<String, String>> entries = new EntrySet(
                DATA.length);

        public Set<Map.Entry<String, String>> entrySet() {
            return entries;
        }
    }

    // Create a partial map of 'size' countries:
    static Map<String, String> select(final int size) {
        return new FlyweightMap() {
            public Set<Map.Entry<String, String>> entrySet() {
                return new EntrySet(size);
            }
        };
    }

    static Map<String, String> map = new FlyweightMap();

    public static Map<String, String> capitals() {
        return map; // The entire map
    }

    public static Map<String, String> capitals(int size) {
        return select(size); // A partial map
    }

    static List<String> names = new ArrayList<String>(map.keySet());

    // All the names:
    public static List<String> names() {
        return names;
    }

    // A partial list:
    public static List<String> names(int size) {
        return new ArrayList<String>(select(size).keySet());
    }

    public static void main(String[] args) {
        print(capitals(10));
        print(names(10));
        print(new HashMap<String, String>(capitals(3)));
        print(new LinkedHashMap<String, String>(capitals(3)));
        print(new TreeMap<String, String>(capitals(3)));
        print(new Hashtable<String, String>(capitals(3)));
        print(new HashSet<String>(names(6)));
        print(new LinkedHashSet<String>(names(6)));
        print(new TreeSet<String>(names(6)));
        print(new ArrayList<String>(names(6)));
        print(new LinkedList<String>(names(6)));
        print(capitals().get("BRAZIL"));
    }
} /*
   * Output: {ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo,
   * BOTSWANA=Gaberone, BULGARIA=Sofia, BURKINA FASO=Ouagadougou,
   * BURUNDI=Bujumbura, CAMEROON=Yaounde, CAPE VERDE=Praia, CENTRAL AFRICAN
   * REPUBLIC=Bangui} [ALGERIA, ANGOLA, BENIN, BOTSWANA, BULGARIA, BURKINA FASO,
   * BURUNDI, CAMEROON, CAPE VERDE, CENTRAL AFRICAN REPUBLIC] {BENIN=Porto-Novo,
   * ANGOLA=Luanda, ALGERIA=Algiers} {ALGERIA=Algiers, ANGOLA=Luanda,
   * BENIN=Porto-Novo} {ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo}
   * {ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo} [BULGARIA, BURKINA FASO,
   * BOTSWANA, BENIN, ANGOLA, ALGERIA] [ALGERIA, ANGOLA, BENIN, BOTSWANA,
   * BULGARIA, BURKINA FASO] [ALGERIA, ANGOLA, BENIN, BOTSWANA, BULGARIA,
   * BURKINA FASO] [ALGERIA, ANGOLA, BENIN, BOTSWANA, BULGARIA, BURKINA FASO]
   * [ALGERIA, ANGOLA, BENIN, BOTSWANA, BULGARIA, BURKINA FASO] Brasilia
   */// :~
